﻿using log4netX.Appender;
using System;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Data;
using MaQiu.SqlExecute.DAL;
using MaQiu.SqlExecute.DbProvider;
using System.Linq;
using System.Configuration;
using System.Globalization;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using MLogHelper.Business;

namespace MLogHelper
{
    internal class StaticInit
    {
        private static readonly decimal _version = 1.0M;
        public static object Lock = new object();
        public static object LockConn = new object();
        private static string todayStr = String.Empty;
        public static bool IsInit { set; get; } = false;
        public static readonly string ConfigFile = AppDomain.CurrentDomain.BaseDirectory + @"\MLogHelper.config";
        public static readonly string LogDir = AppDomain.CurrentDomain.BaseDirectory + @"\TraceLogs\MLog\";
        private static string _connectionString;
        public static string ConnectionString
        {
            get
            {
                lock (LockConn)
                {
                    if (_connectionString == null)
                    {
                        try
                        {
                            Type dataClass = AppDomain.CurrentDomain.GetAssemblies().First(i => i.FullName.StartsWith("Mysoft.Map.Core" + ",")).GetType("Mysoft.Map.Data.MyDB");
                            MethodInfo m = dataClass.GetMethod("GetSqlConnectionString", new Type[] { });
                            string result = (string)m.Invoke(null, null);
                            _connectionString = result;
                        }
                        catch (Exception ex)
                        {
                            var logTxt = "使用的不是Map项目，读取失败，尝试读取小平台，详细情况：" + ex.ToString();
                            LogSimple(logTxt);
                            try
                            {
                                Type dataClass = AppDomain.CurrentDomain.GetAssemblies().First(i => i.FullName.StartsWith("Mysoft.Map.Extensions" + ",")).GetType("Mysoft.Map.Extensions.DAL.ConnectionScope");
                                MethodInfo m = dataClass.GetMethod("GetDefaultConnectionString", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
                                string result = (string)m.Invoke(null, null);
                                if (!string.IsNullOrEmpty(result))
                                    _connectionString = result;
                                else
                                    throw new ApplicationException("没有读取到正确的小平台连接字符串");
                            }
                            catch (Exception x1)
                            {
                                logTxt = "没有小平台，读取失败，尝试读取新平台，详细情况：" + x1.ToString();
                                LogSimple(logTxt);
                                try
                                {
                                    var map6 = AppDomain.CurrentDomain.GetAssemblies()
                                        .First(i => i.FullName.StartsWith("Mysoft.Map6.Core,"));
                                    var typeInfo = map6.GetType("Mysoft.Map6.Core.Pipeline.Data.ConnectionManager");
                                    var info = typeInfo.GetMethod("GetPubPlatformDbConnectionInfo").Invoke(null, null);
                                    _connectionString = map6.GetType("Mysoft.Map6.Core.Pipeline.Data.DbConnectionInfo").GetProperty("LogDb")?.GetValue(info, null).ToString();
                                }
                                catch (Exception x22)
                                {
                                    logTxt = "没有新平台，读取失败，尝试读取配置文件，详细情况：" + x22.ToString();
                                    LogSimple(logTxt);
                                    try
                                    {
                                        _connectionString = ConfigurationManager.AppSettings["MLogConn"].ToString();
                                    }
                                    catch (Exception x)
                                    {
                                        logTxt = "读取配置文件失败，完蛋儿：" + x.ToString();
                                        LogSimple(logTxt);
                                    }
                                }
                            }
                        }
                        return _connectionString;
                    }
                    else
                    {
                        return _connectionString;
                    }
                }
            }
        }

        public static void Init()
        {
            try
            {
                SqlConnection.InitSqlExecute(ConnectionString, new SqlServerProvider());
                StaticInit.InitDataBase();
                StaticInit.InitFile();
                IsInit = true;
            }
            catch (Exception e)
            {
                LogSimple(e.ToString());
            }
        }

        public static void Init(string connectionString)
        {
            if (string.IsNullOrEmpty(connectionString) == false)
            {
                _connectionString = connectionString;
            }
            Init();
        }

        public static void InitFile()
        {
            if (IsInit) return;
            string defaultXml;
            //读取默认配置
            // ReSharper disable once AssignNullToNotNullAttribute
            using (var reader = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("MLogHelper.Res.MLogHelper.config"), Encoding.UTF8))
                defaultXml = reader.ReadToEnd();

            if (File.Exists(ConfigFile))
            {
                //检测是否需要还原默认配置
                try
                {
                    var xml = new XmlDocument();
                    var xmlDefault = new XmlDocument();
                    lock (Lock)
                    {
                        xmlDefault.LoadXml(defaultXml);
                        xml.Load(ConfigFile);
                    }
                    RepalceNode(xml, xmlDefault, "//appender[@name='AdoNetAppender']", "//log4net");
                    RepalceNode(xml, xmlDefault, "//logger[@name='默认日志']", "//log4net");
                    RepalceNode(xml, xmlDefault, "//logger[@name='常规运行日志']", "//log4net");
                    RepalceNode(xml, xmlDefault, "//appender[@name='asyncForwarder1']", "//log4net");
                    RepalceNode(xml, xmlDefault, "//appender[@name='asyncForwarder2']", "//log4net");
                    RepalceNode(xml, xmlDefault, "//appender[@name='默认文件记录器']", "//log4net");
                    RepalceNode(xml, xmlDefault, "//appender[@name='常规文件记录器']", "//log4net");
                    if (xml.OuterXml != File.ReadAllText(ConfigFile))
                    {
                        Configurer.SaveConfigFile(xml.OuterXml);
                    }
                }
                catch (Exception e)
                {
                    LogSimple(e.ToString());
                }
            }
            else
            {
                Configurer.SaveConfigFile(defaultXml);
            }
            var configXml = XElement.Parse(Configurer.GetConfigFileContent());
            string outDays = configXml.Attribute("outdays")?.Value;
            if (int.TryParse(outDays, out int outDayInt))
            {
                DateTime today = DateTime.Today;
                DateTime bgnDay = today.AddDays(outDayInt * -1);
                if (Directory.Exists(LogDir))
                {
                    var fileInfos = new DirectoryInfo(LogDir).GetFiles("*.*");
                    foreach (FileInfo info in fileInfos)
                    {
                        try
                        {
                            var dateStr = info.Name.Substring(info.Name.IndexOf("_") + 1, 8);
                            DateTimeFormatInfo dtFormat = new DateTimeFormatInfo()
                            {
                                ShortDatePattern = "yyyyMMdd"
                            };
                            var d = DateTime.ParseExact(dateStr, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture);
                            if (d < bgnDay)
                            {
                                info.Delete();
                            }
                        }
                        catch (Exception e)
                        {

                        }
                    }
                }
            }

            try
            {
                //从数据库中同步配置信息
                var list = new SqlQuery("SELECT * FROM MyLogXLogger").ToList<MyLogXLogger>();
                foreach (var item in list)
                {
                    var nodes = configXml.Descendants("logger")
                        .Where(i => i.Attribute("name").Value == item.LoggerName);
                    if (nodes.Count() == 0)
                        new Configurer().AddLogger(new Configurer.LoggerConfig()
                        { LoggerName = item.LoggerName, Remarks = item.Remarks, IsOpen = item.IsOpen == 1 });
                    else
                        new Configurer().SetLoggerStatus(item.LoggerName, item.IsOpen == 1);
                }
            }
            catch (Exception)
            {
                LogSimple("从数据库同步配置失败");
            }

            log4netX.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(ConfigFile));
        }

        public static void InitDataBase()
        {
            if (IsInit) return;
            using (var scope = new SqlConnection())
            {
                if (IsInit == false)
                {
                    try
                    {
                        SqlQuery.Create(@"IF OBJECT_ID('MyLogX', 'U') IS NULL
                                    CREATE TABLE MyLogX (
                                        LogXId UNIQUEIDENTIFIER PRIMARY KEY
                                            DEFAULT NEWID(),
                                        [Date] DATETIME,
                                        [Thread] NVARCHAR(200),
                                        [Level] NVARCHAR(200),
                                        [Logger] NVARCHAR(MAX),
                                        [Message] NVARCHAR(MAX),
                                        [Exception] NVARCHAR(MAX),
                                        [TraceStack] NVARCHAR(MAX),
                                        [Url] NVARCHAR(MAX),
                                        [UrlRefer] NVARCHAR(MAX),
                                        [Cookie] NVARCHAR(MAX),
                                        [Session] NVARCHAR(MAX));").ExecuteNonQuery();
                        SqlQuery.Create(@"IF OBJECT_ID('MyLogXLogger', 'U') IS NULL
                                    CREATE TABLE MyLogXLogger (
                                        MyLogXLoggerGUID UNIQUEIDENTIFIER PRIMARY KEY,
                                        LoggerName NVARCHAR(MAX),
                                        Remarks NVARCHAR(MAX),
                                        IsOpen INT );").ExecuteNonQuery();
                        SqlQuery.Create(@"IF NOT EXISTS ( SELECT TOP 1
                                                                1
                                                        FROM    sys.indexes a
                                                        WHERE   a.name = 'idx_MyLogX_Date' )
                                            CREATE NONCLUSTERED INDEX [idx_MyLogX_Date] ON [dbo].[MyLogX]
                                            (
                                            [Date] ASC
                                            );").ExecuteNonQuery();
                        SqlQuery.Create(@"IF OBJECT_ID('MyLogXTriggerChgLog', 'U') IS NULL
                                            CREATE TABLE MyLogXTriggerChgLog ( MyLogXTriggerChgLogGUID UNIQUEIDENTIFIER PRIMARY KEY,
                                                                               KeyGUID UNIQUEIDENTIFIER,
                                                                               LogDate DATETIME,
                                                                               LogSource NVARCHAR(MAX),
                                                                               ExecSql NVARCHAR(MAX),
                                                                               ChgType NVARCHAR(100),
																			   ChgTable NVARCHAR(1000),
                                                                               ChgField NVARCHAR(MAX),
                                                                               BeforeInfo NVARCHAR(MAX),
                                                                               AfterInfo NVARCHAR(MAX));").ExecuteNonQuery();
                        SqlQuery.Create(@"IF OBJECT_ID('MyLogXTriggerChgLogHistory', 'U') IS NULL
                                            CREATE TABLE MyLogXTriggerChgLogHistory ( MyLogXTriggerChgLogGUID UNIQUEIDENTIFIER PRIMARY KEY,
                                                                               KeyGUID UNIQUEIDENTIFIER,
                                                                               LogDate DATETIME,
                                                                               LogSource NVARCHAR(MAX),
                                                                               ExecSql NVARCHAR(MAX),
                                                                               ChgType NVARCHAR(100),
																			   ChgTable NVARCHAR(1000),
                                                                               ChgField NVARCHAR(MAX),
                                                                               BeforeInfo NVARCHAR(MAX),
                                                                               AfterInfo NVARCHAR(MAX));").ExecuteNonQuery();
                        SqlQuery.Create(@"IF NOT EXISTS ( SELECT TOP 1
                                                                1
                                                        FROM    sys.indexes a
                                                        WHERE   a.name = 'idx_MyLogXTriggerChgLog_Date' )
                                            CREATE NONCLUSTERED INDEX [idx_MyLogXTriggerChgLog_Date] ON [dbo].[MyLogXTriggerChgLog]
                                            (
                                            [LogDate] ASC
                                            );").ExecuteNonQuery();
                        SqlQuery.Create(@"IF OBJECT_ID('MyLogXTrigger', 'U') IS NULL
                                                CREATE TABLE MyLogXTrigger ( MyLogXTriggerGUID UNIQUEIDENTIFIER PRIMARY KEY,
                                                                             TriggerName NVARCHAR(4000),
                                                                             Remarks NVARCHAR(4000),
                                                                             AddDateTime DATETIME );").ExecuteNonQuery();

                        SqlQuery.Create(@"if object_id('MyLogXUserAccount', 'U') is null
    begin
        create table MyLogXUserAccount
            (
             UserCode nvarchar(100) primary key
                                    not null ,
             UserPwd nvarchar(500) not null
            );
        insert  into MyLogXUserAccount
                (UserCode, UserPwd)
        values  (N'mysoft', 
                 N'3.1415926'  
                 );
    end;").ExecuteNonQuery();
                        ClearOldLog();
                    }
                    catch (Exception e)
                    {
                        LogSimple("初始化表失败！");
                    }
                }
            }
        }
        internal static void ClearOldLog()
        {
            var today = DateTime.Today.ToString("yyyy-MM-dd");
            try
            {
                if (today == todayStr)
                {
                    return;
                }
                else
                {
                    SqlConnection.InitSqlExecute(StaticInit.ConnectionString, new SqlServerProvider());
                    var sql = SqlQuery.Create(@"DELETE FROM MyLogX WHERE [Date] < DATEADD(m,-3,GETDATE());");
                    sql.GetCommand().CommandTimeout = 10;
                    sql.ExecuteNonQuery();
                    sql = SqlQuery.Create(@"
                                INSERT INTO MyLogXTriggerChgLogHistory (MyLogXTriggerChgLogGUID,KeyGUID,LogDate,LogSource,ExecSql,ChgType,ChgField,BeforeInfo,AfterInfo )
                                SELECT MyLogXTriggerChgLogGUID,KeyGUID,LogDate,LogSource,ExecSql,ChgType,ChgField,BeforeInfo,AfterInfo FROM MyLogXTriggerChgLogHistory
                                WHERE [LogDate] < DATEADD(d,-3,GETDATE());;
                                DELETE FROM MyLogXTriggerChgLog WHERE [LogDate] < DATEADD(d,-3,GETDATE());");
                    sql.GetCommand().CommandTimeout = 10;
                    sql.ExecuteNonQuery();
                    todayStr = today;
                }
            }
            catch (Exception e)
            {
                //删不掉多半就是数据库连不上，也没必要继续连了
                todayStr = today;
            }
        }

        private static void RepalceNode(XmlDocument xml, XmlDocument xmlDefault, string xPath, string parentPath)
        {
            var defaultNode = xmlDefault.SelectSingleNode(xPath);
            var nowNode = xml.SelectSingleNode(xPath);
            if (nowNode != null)
            {
                xml.SelectSingleNode(parentPath).RemoveChild(nowNode);
            }
            var n = xml.ImportNode(defaultNode, true);
            xml.SelectSingleNode(parentPath).AppendChild(n);
        }

        public static void LogSimple(string log)
        {
            var rootPath = "";
            try
            {
                rootPath = System.Web.HttpContext.Current.Server.MapPath(@"~/");
            }
            catch
            {
                rootPath = AppDomain.CurrentDomain.BaseDirectory;
            }
            System.IO.File.AppendAllText(rootPath + @"\MlogDebug.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + log + Environment.NewLine);
        }
    }

    internal class MyLogXLogger
    {
        public Guid MyLogXLoggerGUID { set; get; }
        public string LoggerName { set; get; }
        public string Remarks { set; get; }
        public int IsOpen { set; get; }
    }

    internal class CustomAdoNetAppender : AdoNetAppender
    {
        protected override string ResolveConnectionString(out string connectionStringContext)
        {
            connectionStringContext = StaticInit.ConnectionString;
            return connectionStringContext;
        }
    }
}